#include "PhidgetInterfaceKit.h"
#include "PhidgetManager.h"
#include <stdexcept>


//
// A change was detected on one of the digital inputs.
//
int PhidgetInterfaceKit::InputChangeHandler(CPhidgetInterfaceKitHandle ifk, void *userdata, int index, int value)
{
	PhidgetInterfaceKit *phidget = (PhidgetInterfaceKit *)userdata;
	char valueName[16];
	
	
	if (index < phidget->inputCount)
	{
		phidget->inputs[index] = value;
		snprintf(valueName, 16, "input%d", index);
		phidget->_manager->PhidgetValueChanged(phidget, valueName, phidget->GetPropertyValue(valueName));
	}

    return 0;
}


//
// A change was detected on one of the digital outputs. When we set an output
// value we will be notified once the physical output has changed to match what
// we told it to do.
//
int PhidgetInterfaceKit::OutputChangeHandler(CPhidgetInterfaceKitHandle ifk, void *userdata, int index, int value)
{
	PhidgetInterfaceKit *phidget = (PhidgetInterfaceKit *)userdata;
	char valueName[16];
	
	
	if (index < phidget->outputCount)
	{
		phidget->outputs[index] = value;
		snprintf(valueName, 16, "output%d", index);
		phidget->_manager->PhidgetValueChanged(phidget, valueName, phidget->GetPropertyValue(valueName));
	}

    return 0;
}


//
// A change has been detected on a sensor input.
//
int PhidgetInterfaceKit::SensorChangeHandler(CPhidgetInterfaceKitHandle ifk, void *userdata, int index, int value)
{
	PhidgetInterfaceKit *phidget = (PhidgetInterfaceKit *)userdata;
	char valueName[16];
	
	
	if (index < phidget->sensorCount)
	{
		CPhidgetInterfaceKit_getSensorRawValue(ifk, index, &value);
		phidget->sensors[index] = value;
		snprintf(valueName, 16, "sensor%d", index);
		phidget->_manager->PhidgetValueChanged(phidget, valueName, phidget->GetPropertyValue(valueName));
	}

    return 0;
}



//////////////////////////////////////////////////////////////////////
//
// Phidget private override methods
//
//////////////////////////////////////////////////////////////////////

//
// The interface kit phidget has attached, get some basic information about it.
//
void PhidgetInterfaceKit::AttachHandler()
{
	Phidget::AttachHandler();
	
	if (CPhidgetInterfaceKit_getInputCount((CPhidgetInterfaceKitHandle)handle, &inputCount) != EPHIDGET_OK)
		throw std::runtime_error("New phidget went offline during initialization.");
	if (CPhidgetInterfaceKit_getOutputCount((CPhidgetInterfaceKitHandle)handle, &outputCount) != EPHIDGET_OK)
		throw std::runtime_error("New phidget went offline during initialization.");
	if (CPhidgetInterfaceKit_getSensorCount((CPhidgetInterfaceKitHandle)handle, &sensorCount) != EPHIDGET_OK)
		throw std::runtime_error("New phidget went offline during initialization.");

	//
	// Make sure we don't have more inputs/outputs/sensors than we can
	// internally handle.
	//
	if (inputCount > PIK_MAXCOUNT)
		inputCount = PIK_MAXCOUNT;
	if (outputCount > PIK_MAXCOUNT)
		outputCount = PIK_MAXCOUNT;
	if (sensorCount > PIK_MAXCOUNT)
		sensorCount = PIK_MAXCOUNT;

	//
	// Set the sensor rate to only trigger every other value.
	//
	for (int i = 0; i < sensorCount; i++)
	{
		CPhidgetInterfaceKit_setSensorChangeTrigger((CPhidgetInterfaceKitHandle)handle, i, 1);
		CPhidgetInterfaceKit_setDataRate((CPhidgetInterfaceKitHandle)handle, i, 250);
	}
}



//////////////////////////////////////////////////////////////////////
//
// PhidgetInterfaceKit public methods
//
//////////////////////////////////////////////////////////////////////

//
// Initialize a new InterfaceKit type phidget. This is a "live" constructor
// meaning the device must be online and attached to initialize it.
//
PhidgetInterfaceKit::PhidgetInterfaceKit(int serial, PhidgetManager *manager)
{
	//
	// Initialize the phidget.
	//	
	CPhidgetInterfaceKit_create((CPhidgetInterfaceKitHandle *)&handle);
	CommonInit();

	//
	// Setup each of the "on change" handlers.
	//
    if (CPhidgetInterfaceKit_set_OnInputChange_Handler((CPhidgetInterfaceKitHandle)handle, PhidgetInterfaceKit::InputChangeHandler, this) != EPHIDGET_OK)
    	throw std::runtime_error("New phidget went offline during initialization.");
    if (CPhidgetInterfaceKit_set_OnOutputChange_Handler((CPhidgetInterfaceKitHandle)handle, OutputChangeHandler, this) != EPHIDGET_OK)
    {
	    CPhidgetInterfaceKit_set_OnInputChange_Handler((CPhidgetInterfaceKitHandle)handle, NULL, NULL);
	    throw std::runtime_error("New phidget went offline during initialization.");
    }
    if (CPhidgetInterfaceKit_set_OnSensorChange_Handler((CPhidgetInterfaceKitHandle)handle, SensorChangeHandler, this) != EPHIDGET_OK)
    {
	    CPhidgetInterfaceKit_set_OnOutputChange_Handler((CPhidgetInterfaceKitHandle)handle, NULL, NULL);
	    CPhidgetInterfaceKit_set_OnInputChange_Handler((CPhidgetInterfaceKitHandle)handle, NULL, NULL);
	    throw std::runtime_error("New phidget went offline during initialization.");
    }

	//
	// Open the phidget in the background.
	//
   	manager->OpenPhidgetHandle(handle, serial);
   	_manager = manager;
}



//////////////////////////////////////////////////////////////////////
//
// Public methods that override base behavior.
//
//////////////////////////////////////////////////////////////////////

//
// Retrieve a list of the properties supported by this phidget.
//
std::list<std::string> PhidgetInterfaceKit::SupportedProperties()
{
	std::list<std::string> properties;
	char string[40];
	int i;
	

	//
	// Add the digital inputs to the property list.
	//	
	for (i = 0; i < inputCount; i++)
	{
		snprintf(string, 40, "input%d", i);
		properties.push_back(std::string(string));
	}
	
	//
	// Add the digital outputs to the property list.
	//	
	for (i = 0; i < inputCount; i++)
	{
		snprintf(string, 40, "output%d", i);
		properties.push_back(std::string(string));
	}
	
	//
	// Add the sensors to the property list.
	//	
	for (i = 0; i < inputCount; i++)
	{
		snprintf(string, 40, "sensor%d", i);
		properties.push_back(std::string(string));
	}
	
	return properties;
}


//
// Get the value of the named property.
//
std::string PhidgetInterfaceKit::GetPropertyValue(std::string property)
{
	char string[40];
	int index;


	//
	// Process digital input properties.
	//
	if (property.size() > 5 && property.substr(0, 5) == "input")
	{
		index = atoi(property.substr(0, 5).c_str());
		if (index < inputCount)
			snprintf(string, 40, "%d", inputs[index]);
		else
			snprintf(string, 40, "0");
			
		return std::string(string);
	}
	
	//
	// Process digital output properties.
	//
	if (property.size() > 6 && property.substr(0, 6) == "output")
	{
		index = atoi(property.substr(0, 6).c_str());
		if (index < outputCount)
			snprintf(string, 40, "%d", outputs[index]);
		else
			snprintf(string, 40, "0");
			
		return std::string(string);
	}

	//
	// Process sensor properties, return value as 0.0 - 5.0 (volts)
	//
	if (property.size() > 6 && property.substr(0, 6) == "sensor")
	{
		index = atoi(property.substr(0, 6).c_str());
		if (index < sensorCount)
			snprintf(string, 40, "%d", sensors[index]);
		else
			snprintf(string, 40, "0");
			
		return std::string(string);
	}

	return std::string("");
}


//
// Set the value of the named property.
//
void PhidgetInterfaceKit::SetPropertyValue(std::string property, std::string value)
{
	int index, nValue = 0;
	
	
	//
	// Process digital output properties.
	//
	if (property.size() > 6 && property.substr(0, 6) == "output")
	{
		index = atoi(property.substr(0, 6).c_str());
		nValue = atoi(value.c_str());
		
		CPhidgetInterfaceKit_setOutputState((CPhidgetInterfaceKitHandle)handle, index, (nValue != 0));
	}
}

